package com.googlecode.maratische.google;

import static com.googlecode.maratische.google.MainController.getMainController;

import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

import javax.swing.SwingUtilities;

import org.apache.log4j.Logger;

import be.lechtitseb.google.reader.api.core.GoogleReader;
import be.lechtitseb.google.reader.api.model.authentication.GoogleCredentials;
import be.lechtitseb.google.reader.api.model.authentication.ProxyCredentials;
import be.lechtitseb.google.reader.api.model.exception.AuthenticationException;
import be.lechtitseb.google.reader.api.model.exception.GoogleReaderException;

import com.googlecode.maratische.google.dao.PropertyDao;
import com.googlecode.maratische.google.listeners.DisplayPaneListener;
import com.googlecode.maratische.google.listeners.DisplayPaneObservable;
import com.googlecode.maratische.google.listeners.LoginListener;
import com.googlecode.maratische.google.listeners.LoginObservable;
import com.googlecode.maratische.google.listeners.MainFrameListener;
import com.googlecode.maratische.google.listeners.MainFrameObservable;
import com.googlecode.maratische.google.listeners.SelectItemListener;
import com.googlecode.maratische.google.listeners.SelectItemObservable;
import com.googlecode.maratische.google.listeners.SpinnerListener;
import com.googlecode.maratische.google.listeners.SpinnerObservable;
import com.googlecode.maratische.google.model.Command;
import com.googlecode.maratische.google.model.CommandReadItem;
import com.googlecode.maratische.google.model.CommandRemoveReadedItemMedia;
import com.googlecode.maratische.google.model.CommandSearchSpammedItem;
import com.googlecode.maratische.google.model.CommandStarredItem;
import com.googlecode.maratische.google.model.CommandUnStarredItem;
import com.googlecode.maratische.google.model.CommandUpdateFeedOffline;
import com.googlecode.maratische.google.model.CommandUpdateFeedOnline;
import com.googlecode.maratische.google.model.CommandUpdateFullItem;
import com.googlecode.maratische.google.model.Commands;
import com.googlecode.maratische.google.model.Constants;
import com.googlecode.maratische.google.model.Credentials;
import com.googlecode.maratische.google.model.Feed;
import com.googlecode.maratische.google.model.Item;
import com.googlecode.maratische.google.model.Label;
import com.googlecode.maratische.google.model.Property;
import com.googlecode.maratische.google.model.Spam;
import com.googlecode.maratische.google.utils.DesktopUtil;

/**
 * Controller for all Actions
 * 
 * @author gizatullinm
 * 
 *         http://wiki.linuxformat.ru/index.php/LXF92:Java_EE
 */
public class MainController {

	static Logger logger = Logger.getLogger(MainController.class.getName());

	private static MainController controller = null;
	private DisplayPaneObservable displayPaneObservable = new DisplayPaneObservable();
	private MainFrameObservable mainFrameObservable = new MainFrameObservable();
	private SpinnerObservable spinnerObservable = new SpinnerObservable();
	private LoginObservable loginObservable = new LoginObservable();
	private SelectItemObservable selectItemObservable = new SelectItemObservable();
	private Boolean offlineStatus = null;
	private Boolean feedMenuViewAllStatus = null;
	private Boolean itemMenuViewAllStatus = null;
	private Integer displayPaneFontSize = null;
	private Feed selectedFeed = null;
	private Item selectedItem = null;
	private List<Item> selectedItems;
	private Locale currentLocale;
	private ResourceBundle messages;
	private ResourceBundle messagesDefault;


	private MainController() {
	}

	public static MainController getMainController() {
		if (controller == null) {
			controller = new MainController();
		}
		return controller;
	}

	boolean isFullScreen = false;
	MainFrame frame = null;

	public void startMainFrame() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				try {
					if (frame != null) {
						frame.dispose();
					}
					frame = new MainFrame();
					frame.setVisible(true);
				} catch (Exception e) {
					MainFrame mainFrame = new MainFrame(e);
					mainFrame.dispose();
				}
			}
		});
	}
	
	/**
	 * стартует после инициализации формы
	 */
	public void afterStartMainFrame() {
		//проверяем наличие сохраненной авторизации
		Property propertyAuth;
		try {
			propertyAuth = DaoAction.getDaoAction().getPropertyDao().getPropertyByType(Property.PROPERTY_AUTH);
			if (propertyAuth.getString1().length() > 0) {
				loginObservable.login();
			} else {
				loginObservable.logout();
			}
		} catch (BaseException e) {
			showError(getBundleMessage("mainframe.error.init"), e);
		}
		
		try {
			showHelp();
		} catch (Exception e) {
			showError(e);
		}
	}

	public void logout() throws BaseException {
		saveLogin(null, null, null, null);
		getDaoAction().setGoogleReader(null);
		loginObservable.logout();
	}

	public GoogleReader login() throws BaseException {
		return login(null);
	}

	/**
	 * Login in Google Reader
	 * 
	 * @throws BaseException
	 */
	private GoogleReader login(String errorMessage) throws BaseException {
		PropertyDao propertyDao = DaoAction.getDaoAction().getPropertyDao(); 
		//proxy
		ProxyCredentials proxyCredentials = null;
		if (propertyDao.getPropertyByType(Property.PROPERTY_PROXY_ENABLED).getInteger1().equals(1)) {
			proxyCredentials = new ProxyCredentials();
			String login = propertyDao.getPropertyByType(Property.PROPERTY_PROXY_LOGIN).getString1();
			if (login.length()>0) {
				proxyCredentials.setLogin(login);
				proxyCredentials.setPassword(propertyDao.getPropertyByType(Property.PROPERTY_PROXY_PASSWORD).getString1());
			}
			proxyCredentials.setHost(propertyDao.getPropertyByType(Property.PROPERTY_PROXY_HOST).getString1());
			proxyCredentials.setPort(propertyDao.getPropertyByType(Property.PROPERTY_PROXY_PORT).getInteger1());
		}
		
		// необходимо проверить валидность уже имеющихся ключей, если не
		// подходят - обновиться и запросить у пользователя
		Property propertyAuth= propertyDao.getPropertyByType(Property.PROPERTY_AUTH);
		Property propertyLogin = propertyDao.getPropertyByType(Property.PROPERTY_LOGIN);
//		String auth = getProperties().getProperty(PROPERTY_AUTH);
		if (propertyAuth.getString1().length() > 0) {
			GoogleCredentials googleCredentials = new GoogleCredentials(propertyLogin.getString1(), null);
			googleCredentials.setAuth(propertyAuth.getString1());
			
			Property propertySid= propertyDao.getPropertyByType(Property.PROPERTY_SID);
			googleCredentials.setSid(propertySid.getString1());
			
			Property propertyLSid= propertyDao.getPropertyByType(Property.PROPERTY_L_SID);
			googleCredentials.setLSid(propertyLSid.getString1());
			
			GoogleReader googleReader = new GoogleReader(googleCredentials, proxyCredentials);
			try {
				googleReader.login();
				loginObservable.login();
				return googleReader;
			} catch (AuthenticationException e) {
				// reset данных
				propertyDao.remove(propertyAuth);
			}

		}
		// получение данных у польхователя
		Credentials credentials = mainFrameObservable.loginForm(errorMessage);
		if (credentials != null) {
			GoogleReader googleReader = new GoogleReader(credentials.getUserName(), credentials.getPassword(), proxyCredentials);
			try {
				googleReader.login();
				if (credentials.getSaveSession()) {
					saveLogin(credentials.getUserName(), googleReader.getCredentials().getAuth(), googleReader.getCredentials().getSid(),
							googleReader.getCredentials().getLSid());
				} else {
					saveLogin(credentials.getUserName(), null, null, null);
				}
				loginObservable.login();
			} catch (AuthenticationException e) {
				login("Error login!");
			} catch (BaseException e) {
				showError("Ошибка при сохранении параметров", e);
			}
			return googleReader;
		}
		return null;
	}

	/**
	 * показаваем всплывающее информационное окно, для показа пользователю. мол добавим ленту, 
	 * если ее еще ни разу не добавляли и не открывали.
	 */
	public void showInfWindowAddOfflineMode(Feed selectedFeed) {
		selectItemObservable.showInfWindowAddOfflineMode(selectedFeed);
	}
	
	public void showInfWindowCheckNewFeeds(final List<Feed> newFeeds) {
		selectItemObservable.showInfWindowCheckNewFeeds(newFeeds);
	}
	
	public void showWindowTreeAddNewFeeds() {
		selectItemObservable.showWindowTreeAddNewFeeds();
	}
	
	public void disableInfWindow() {
		selectItemObservable.disableInfWindow();
	}
	
	/**
	 * возвращает сообщение в локали пользователя.
	 * Если локаль еще не выбрана, получает ее из настроек,
	 * если же в настройках нет локали, а текущая системная локаль отсутствует в наших возможных, 
	 * то используется English
	 * @param message
	 * @return
	 */
	public String getBundleMessage(String message) {
		if (messages == null) {
			StringBuilder fileName = new StringBuilder("/MessagesBundle_").append(getCurrentLocale().toString()).append(".properties");
			try {
				messagesDefault = new PropertyResourceBundle(new InputStreamReader(getClass().getResourceAsStream("/MessagesBundle_en_US.properties"),Charset.forName("UTF-8")));
				messages = new PropertyResourceBundle(new InputStreamReader(getClass().getResourceAsStream(fileName.toString()),Charset.forName("UTF-8")));
			} catch (IOException e) {
				setCurrentLocale(new Locale("en", "US"));
			}
		}
		if (messages != null) {
			try {
				return messages.getString(message);
			} catch (MissingResourceException e) {
				try {
				return messagesDefault.getString(message);
				} catch (MissingResourceException e1) {
					return message;
				}
			}
		}
		return message;
	}
	
	public Locale[] getSupportedLocales() {
		List<Locale> supportList = new ArrayList<Locale>();
		Locale[] list = DateFormat.getAvailableLocales();
		for (Locale locale : list) {
			StringBuilder fileName = new StringBuilder("/MessagesBundle_").append(locale.toString()).append(".properties");
				URL urlResource = getClass().getResource(fileName.toString());
				if (urlResource != null) {
					supportList.add(locale);
				}
		}
		return supportList.toArray(new Locale[] {});
	}
	
	public void openLabelFormForSelectedItem() throws SQLException, BaseException {
		Item selectedItem = getSelectedItem();
		if (selectedItem != null) {
			if (selectedItem.getFeedId() == null) {
				showError("Сохранение метки возможно только для лент с offline поддержкой", null);
				return;
			}
			Feed feed = null;
			if (selectedItem.getFeedId() != null) {
				feed = getDaoAction().getFeedDao().get(selectedItem.getFeedId());
			}
			if (selectedItem.getLabelId() == null) {
				Label label = mainFrameObservable.openLabelForm(selectedItem);
				if (label != null) {
					label = getDaoAction().getLabelDao().save(label);
					selectedItem.setLabelId(label.getId());
					selectedItem = getDaoAction().getItemDao().save(selectedItem);
					this.selectedItem = selectedItem;
					CommandStarredItem command = (CommandStarredItem)Command.createCommand(Commands.STARRED_ITEM);
					command.setString1(selectedItem.getUri());
					command.setString2(feed.getFeedDescriptorId());
					CommandProcessor.getCommandProcessor().createCommand(command);
					CommandUpdateFullItem command2 = (CommandUpdateFullItem)Command.createCommand(Commands.UpdateFullItem);
					command2.setInteger1(selectedItem.getId());
					CommandProcessor.getCommandProcessor().createCommand(command2);

					mainFrameObservable.updateFeedMenu();
				}
			} else {
				if (mainFrameObservable.openNotLabelForm(selectedItem)) {
					selectedItem.setLabelId(null);
					selectedItem = getDaoAction().getItemDao().save(selectedItem);
					getDaoAction().getLabelDao().remove(selectedItem.getLabelId());
					this.selectedItem = selectedItem;

					CommandUnStarredItem command = (CommandUnStarredItem)Command.createCommand(Commands.UN_STARRED_ITEM);
					command.setString1(selectedItem.getUri());
					command.setString2(feed.getFeedDescriptorId());
					CommandProcessor.getCommandProcessor().createCommand(command);

					mainFrameObservable.updateFeedMenu();
				}
			}
			//надо обновить значек на ItemsPanelJJList
			selectItemObservable.updateItemStringForCurrentItem();
		}
	}

	/**
	 * сравниваем параметры и если не совпадают - сохраняем новые
	 * 
	 * @param size
	 * @throws SQLException
	 */
	public void checkProperty(Dimension size, int mainPaneDividerLocation, int rightPaneDividerLocation) throws BaseException, SQLException {
		PropertyDao propertyDao = DaoAction.getDaoAction().getPropertyDao();
		// правый горизонтальный разделитель
		Property propertyRightDivided = propertyDao.getPropertyByType(Property.PROPERTY_RIGHTPANE_DIVIDER);
		if (rightPaneDividerLocation != 1 && !propertyRightDivided.getInteger1().equals(new Integer(rightPaneDividerLocation))) {
			propertyRightDivided.setInteger1(new Integer(rightPaneDividerLocation));
			propertyDao.save(propertyRightDivided);
		}
		// вертикальный разделитель
		Property propertymainDivided = propertyDao.getPropertyByType(Property.PROPERTY_MAINPANE_DIVIDER);
		if (mainPaneDividerLocation != 1 && !propertymainDivided.getInteger1().equals(new Integer(mainPaneDividerLocation))) {
			propertymainDivided.setInteger1(new Integer(mainPaneDividerLocation));
			propertyDao.save(propertymainDivided);
		}
		// Ширина формы
		Property propertyWidth = propertyDao.getPropertyByType(Property.PROPERTY_FORM_WIDTH);
		if (!propertyWidth.getInteger1().equals(new Integer((int) size.getWidth()))) {
			propertyWidth.setInteger1(new Integer((int) size.getWidth()));
			propertyDao.save(propertyWidth);
		}
		// Высота формы
		Property propertyHeight = propertyDao.getPropertyByType(Property.PROPERTY_FORM_HEIGHT);
		if (!propertyHeight.getInteger1().equals(new Integer((int) size.getHeight()))) {
			propertyHeight.setInteger1(new Integer((int) size.getHeight()));
			propertyDao.save(propertyHeight);
		}
		// offline support
		Property propertyOffline = DaoAction.getDaoAction().getPropertyDao().getPropertyByType(Property.PROPERTY_OFFLINE_STATUS);
		int offline = getOfflineStatus() ? 1 : 0;
		if (!propertyOffline.getInteger1().equals(offline)) {
			propertyOffline.setInteger1(offline);
			propertyDao.save(propertyOffline);
		}
		// размер шрифта
		Property propertyFontSize = propertyDao.getPropertyByType(Property.PROPERTY_DISPLAY_PANE_FONT_SIZE);
		if (!propertyFontSize.getInteger1().equals(getDisplayPaneFontSize())) {
			propertyFontSize.setInteger1(getDisplayPaneFontSize());
			propertyDao.save(propertyFontSize);
		}
	}

	private void saveLogin(String login, String auth, String sid, String lSid) throws BaseException {
		try {
			PropertyDao propertyDao = DaoAction.getDaoAction().getPropertyDao(); 
			Property propertyLogin = propertyDao.getPropertyByType(Property.PROPERTY_LOGIN);
			if (login != null && !login.equals(propertyLogin.getString1())) {
				propertyLogin.setString1(login);
				propertyDao.save(propertyLogin);
			}
			Property propertyAuth = propertyDao.getPropertyByType(Property.PROPERTY_AUTH);
			if (auth != null) {
				propertyAuth.setString1(auth);
				propertyDao.save(propertyAuth);
			} else {
				propertyDao.remove(propertyAuth);
			}
			Property propertySid = propertyDao.getPropertyByType(Property.PROPERTY_SID);
			if (sid != null) {
				propertySid.setString1(sid);
				propertyDao.save(propertySid);
			} else {
				propertyDao.remove(propertySid);
			}
			Property propertyLSid = propertyDao.getPropertyByType(Property.PROPERTY_L_SID);
			if (lSid != null) {
				propertyLSid.setString1(lSid);
				propertyDao.save(propertyLSid);
			} else {
				propertyDao.remove(propertyLSid);
			}
		} catch (SQLException e) {
			throw new BaseException(e.getMessage());
		}
	}

	public Feed getSelectedFeed() {
		return this.selectedFeed;
	}

	public void showSpanFormForSelectedItem() {
		if (getSelectedItem() != null) {
			Spam spam = mainFrameObservable.openSpamForm();
			if (spam != null) {
				//TODO проверить, вдруг такой уже есть
				try {
					spam = getDaoAction().getSpamDao().save(spam);
					CommandSearchSpammedItem command = (CommandSearchSpammedItem)Command.createCommand(Commands.SearchSpammedItem);
					command.setInteger1(spam.getId());
					command.execute(getDaoAction());
				} catch (SQLException e) {
					showError(e);
				} catch (BaseException e) {
					showError(e);
				} catch (GoogleReaderException e) {
					showError(e);
				}
			}
		}
	}
	
	public void showHelp() throws Exception {
		StringBuilder fileName = new StringBuilder("/help_").append(getCurrentLocale().toString()).append(".html");
		BufferedReader br = new BufferedReader(new InputStreamReader(getClass().getResource(fileName.toString()).openStream(), Charset.forName("UTF-8")));
		String temp = null;
		StringBuffer sb = new StringBuffer();
		while ((temp = br.readLine()) != null) {
			sb.append(temp);
		}
		displayPaneObservable.setText(sb.toString());

		/**
		 * TODO временно, для удобства тестирования
		 */
		showInfWindowAddOfflineMode(null);
		/*
		 * File fileHelp = new
		 * File(getClass().getResource("/help_ru.html").toURI()); if
		 * (fileHelp.exists()) { BufferedReader br = new BufferedReader(new
		 * FileReader(fileHelp)); String temp = null; StringBuffer sb = new
		 * StringBuffer(); while ( (temp = br.readLine()) != null) {
		 * sb.append(temp); } displayPaneObservable.setText(sb.toString()); }
		 * else { displayPaneObservable.setText("файл помощи отсутствует"); }
		 */
	}

	/**
	 * Смена типа поддержки для ленты
	 * 
	 * @param value
	 */
	public void changeOfflineSupportForSelectedFeed(Boolean value) {
		changeOfflineSupportForSelectedFeed(this.selectedFeed, value);
	}
	public void changeOfflineSupportForSelectedFeed(Feed feed,Boolean value) {
		if (feed == null) {
			return;
		}
		feed.setOfflineSupport(value);
		try {
			getDaoAction().getFeedDao().save(feed);
		} catch (SQLException e2) {
			mainFrameObservable.showError(e2);
		} catch (BaseException e) {
			mainFrameObservable.showError(e);
		}
		if (value.booleanValue()) {
			if (feed.getFeedDescriptorId() != null && feed.getFeedDescriptorId().length() > 0) {
				CommandUpdateFeedOffline command;
				try {
					command = (CommandUpdateFeedOffline) Command.createCommand(Commands.UpdateFeedOffline);
					command.setString1(feed.getFeedDescriptorId());
					CommandProcessor.getCommandProcessor().createCommand(command);
				} catch (BaseException e) {
					mainFrameObservable.showError(e);
				} catch (SQLException e) {
					mainFrameObservable.showError(e);
				}
			}
		} else {
			try {
				getDaoAction().getFeedDao().save(feed);
				List<Item> items = getDaoAction().getItemDao().findByFeedId(feed.getId());
				if (items != null && items.size() > 0) {
					for (Item item : items) {
						CommandRemoveReadedItemMedia command = (CommandRemoveReadedItemMedia) Command
								.createCommand(Commands.RemoveReadedItemMedia);
						command.setInteger1(item.getId());
						CommandProcessor.getCommandProcessor().createCommand(command);
					}
				}
			} catch (Exception e) {
				mainFrameObservable.showError(e);
			}
		}
		updateFeedMenu();
	}

	/**
	 * Выделение Ленты
	 * 
	 * @param selectedFeed
	 * @throws Exception
	 */
	public void selectFeed(Feed selectedFeed) throws Exception {
		selectItem(null);
		disableInfWindow();
		this.selectedFeed = selectedFeed;
		if (selectedFeed != null) {
			if (!selectedFeed.isFolder()) {
				if (this.selectedFeed.getId().equals(Constants.RSS_READER_LABELED_FEED)) {
					setItemsToItemList(getDaoAction().getItemDao().listAllLabeled());
				} else if (this.selectedFeed.getId().equals(Constants.RSS_READER_LABELED_READ)) {
					setItemsToItemList(getDaoAction().getItemDao().listLabeledByType(Label.LABEL_TYPE_READ));
				} else if (this.selectedFeed.getId().equals(Constants.RSS_READER_LABELED_COMMENT)) {
					setItemsToItemList(getDaoAction().getItemDao().listLabeledByType(Label.LABEL_TYPE_COMMENT));
				} else if (this.selectedFeed.getId().equals(Constants.RSS_READER_LABELED_PRINT)) {
					setItemsToItemList(getDaoAction().getItemDao().listLabeledByType(Label.LABEL_TYPE_PRINT));
				} else if (this.selectedFeed.getOfflineSupport() != null && this.selectedFeed.getOfflineSupport().booleanValue()) {
					// load from database
					try {
						if (getItemMenuViewAllStatus()) {
							setItemsToItemList(getDaoAction().getItemDao().findByFeedId(selectedFeed.getId()));
						} else {
							setItemsToItemList(getDaoAction().getItemDao().findByFeedIdUnread(selectedFeed.getId()));
							
						}
					} catch (SQLException e) {
						mainFrameObservable.showError(e);
					}
				} else {
					setItemsToItemList(null);
					// create command
					CommandUpdateFeedOnline command = (CommandUpdateFeedOnline) Command.createCommand(Commands.UpdateFeedOnline);
					command.setString1(selectedFeed.getFeedDescriptorId());
					CommandProcessor.getCommandProcessor().createCommand(command);
					//показывать вопрос про окна, если еще не спрашивали
					if (this.selectedFeed.getOfflineSupport() == null) {
						showInfWindowAddOfflineMode(selectedFeed);
					}
				}
			} else {
				// обновляется папка
				List<Feed> feeds = getDaoAction().getFeedDao().findByParentId(selectedFeed.getId());
				List<Item> items = new ArrayList<Item>();
				for (Feed feed : feeds) {
					if (feed.getUnreadItems() > 0) {
						if (getItemMenuViewAllStatus()) {
//							items.addAll(addFeedNameToItemTitle(getDaoAction().getItemDao().findByFeedId(feed.getId()), feed.getName()));
							items.addAll(getDaoAction().getItemDao().findByFeedId(feed.getId()));
						} else {
//							items.addAll(addFeedNameToItemTitle(getDaoAction().getItemDao().findByFeedIdUnread(feed.getId()),feed.getName()));
							items.addAll(getDaoAction().getItemDao().findByFeedIdUnread(feed.getId()));
						}
					}
				}
				Collections.sort(items, new Comparator<Item>() {
					public int compare(Item o1, Item o2) {
						Date d1 = o1.getUpdatedDate();
						Date d2 = o2.getUpdatedDate();
						if (d1 == null) {
							return 1;
						}
						if (d2 == null) {
							return -1;
						}
						return d1.compareTo(d2) * -1;
					}
				});
				setItemsToItemList(items);
			}
/*			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					mainFrameObservable.updateItemsPanel();
				}
			});*/
		}

	}


	/**
	 * выбор левого(предыдущего) значения в списке просматриваемых элементов
	 */
	public void itemsListSelectLeft() {
		selectItemObservable.selectLeft();
	}
	
	/**
	 * выбор правого значения в списке просматриваемых элементов
	 */
	public void itemsListSelectRight() {
		selectItemObservable.selectRight();
	}
	public boolean itemsListCanRight() {
		return selectItemObservable.canRight();
	}
	public boolean itemsListCanLeft() {
		return selectItemObservable.canLeft();
	}
	
	/**
	 * К каждому Item в его название добавляем название его ленты (Feed)
	 * 
	 * @param items
	 * @param feedName
	 * @return
	 */
	private List<Item> addFeedNameToItemTitle(List<Item> items, String feedName) {
		if (feedName != null && feedName.length() > 0) {
			if (feedName.length() > 35) {
				feedName = feedName.substring(0, 35);
			}
		}
		for (Item item : items) {
			item.setTitle(new StringBuffer(feedName).append(" / ").append(item.getTitle()).toString());
		}
		return items;
	}

	public void selectItems(List<Item> selectedItems) throws Exception {
		this.selectedItems = selectedItems;
	}
	/**
	 * Выделение конкретного Item
	 * 
	 * @param selectedItem
	 * @param selectedFeed
	 * @throws Exception
	 */
	public void selectItem(Item selectedItem) throws Exception {
		this.selectedItem = selectedItem;
		displayPaneObservable.setDisplayedItem(null);

		if (selectedItem != null) {
			try {
				displayPaneObservable.setDisplayedItem(selectedItem);
				markItemAsRead(selectedItem);
			} catch (Exception e) {
				logger.info("Не преодолимая ошибка открытия странички " + e.getMessage());
				mainFrameObservable.showError("Не преодолимая ошибка открытия странички ", e);
			}
			selectItemObservable.updateItemMarkAsReadCurrentItem();
		} else {
			mainFrameObservable.itemsPanelClearSelection();
		}
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				updateItemsPanel();
				updateFeedMenu();
			}
		});
	}

	public void copySelectedItemUrlToClipboard() {
		if (this.getSelectedItem() != null) {
			String url = getURIForSelectedItem();
			StringSelection stringSelection = new StringSelection( url );
		    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
		    clipboard.setContents( stringSelection, null);
			
		}
//		Clipboard clipboard = new Clipboard(arg0);
		//TODO CLippboard
	}
	
	public void openInBrowserSelectItem() throws IOException, URISyntaxException {
		if (this.getSelectedItem() != null) {
			String url = getURIForSelectedItem();
			DesktopUtil.openUrlInBrowser(url);
		}
	}

	private String getURIForSelectedItem() {
		String url = null;
		if (this.getSelectedItem().getLabelId() != null) {
			try {
				Label label = DaoAction.getDaoAction().getLabelDao().get(this.getSelectedItem().getLabelId());
				if (label != null && label.getFileSaved() != null && label.getFileSaved().length()>0) {
					url = new File(label.getFileSaved()).toURI().toString();
				}
			} catch (SQLException e) {
				showError(e);
			} catch (BaseException e) {
				showError(e);
			}
			
		}
		if (url == null) {
			url = this.getSelectedItem().getLink();
		}
		return url;
	}

	public void openSourceCodeSelectItem() {
		if (this.getSelectedItem() != null) {
			mainFrameObservable.viewSourceCodeFrame(this.getSelectedItem().getTitle(), this.getSelectedItem().getDescription());
		}
	}

	public Item getSelectedItem() {
		return this.selectedItem;
	}

	public void markSelectedItemsAsRead() {
		if (this.selectedItems == null) {
			markItemAsRead(this.selectedItem);
		} else {
			for (Item item : this.selectedItems) {
				markItemAsRead(item);
			}
		}
		updateItemsPanel();
		updateFeedMenu();
	}
	
	public void markItemAsRead(Item item) {
		markItemAsRead(item, this.selectedFeed);
	}
	public void markItemAsRead(Item item, Feed feed) {
		if (!item.isRead()) {
			SwingUtilities.invokeLater(new ItemSelectorInThread(item, feed) {
				public void run() {
					try {
						if (item.getFeedId() != null) {
							feed = getDaoAction().getFeedDao().get(item.getFeedId());
						}
						if (item.getUri() == null || item.getUri().length()==0 
								||feed.getFeedDescriptorId() == null || feed.getFeedDescriptorId().length()==0) {
							throw new BaseException("error on create ReadItem Command. Item:"+item.getUri()+" Feed:"+feed.getFeedDescriptorId());
						}
						CommandReadItem command = (CommandReadItem) Command.createCommand(Commands.ReadItem);
						command.setString1(item.getUri());
						if ("people_you_follow".equals(feed.getFeedDescriptorId())) {
							String feedDescriptorId = item.getSourceUri();
							if (feedDescriptorId.indexOf("tag:google.com,2005:reader/")==0) {
								feedDescriptorId = feedDescriptorId.substring("tag:google.com,2005:reader/".length());
							}
							command.setString2(feedDescriptorId);
						} else {
							command.setString2(feed.getFeedDescriptorId());
						}
						CommandProcessor.getCommandProcessor().createCommand(command);
						feed.setUnreadItems(feed.getUnreadItems() - 1);
						getDaoAction().getFeedDao().save(feed);
						item.setRead(true);
						item.setReadedDate(new java.sql.Date(new java.util.Date().getTime()));
						if (item.getId() != null) {
							getDaoAction().getItemDao().save(item);
						}
					} catch (Exception e1) {
						mainFrameObservable.showError(e1);
					}
				}
			});
		}
	}

	abstract class ItemSelectorInThread extends Thread {
		Item item;
		Feed feed;

		public ItemSelectorInThread(Item item, Feed feed) {
			this.item = item;
			this.feed = feed;
			setPriority(getPriority()-5);
		}
	}

	public void changeOfflineStatus() throws BaseException {
		changeOfflineStatus(!this.getOfflineStatus());
	}

	public void changeOfflineStatus(boolean offlineStatus) throws BaseException {
		this.offlineStatus = offlineStatus;
		mainFrameObservable.updateOfflineButton();
		CommandProcessor commandProcessor = CommandProcessor.getCommandProcessor();
		commandProcessor.setOfflineStatus(offlineStatus);
		commandProcessor.ping();
	}

	public void setDisplayPaneFontSize(Integer fontSize) {
		this.displayPaneFontSize = fontSize;
	}

	public Integer getDisplayPaneFontSize() throws BaseException {
		if (displayPaneFontSize == null) {
			Property propertyDisplayPaneFontSize = DaoAction.getDaoAction().getPropertyDao()
					.getPropertyByType(Property.PROPERTY_DISPLAY_PANE_FONT_SIZE);
			displayPaneFontSize = propertyDisplayPaneFontSize.getInteger1();
		}
		return displayPaneFontSize;
	}

	public void setFeedMenuViewAllStatus(boolean status) throws SQLException {
		feedMenuViewAllStatus = status;
	}

	public boolean getFeedMenuViewAllStatus() throws BaseException {
		if (feedMenuViewAllStatus == null) {
			Property propertyFeedMenuViewAll = DaoAction.getDaoAction().getPropertyDao()
					.getPropertyByType(Property.PROPERTY_FEED_MENU_VIEW_ALL);
			if (propertyFeedMenuViewAll.getInteger1().equals(1)) {
				feedMenuViewAllStatus = Boolean.TRUE;
			} else {
				feedMenuViewAllStatus = Boolean.FALSE;
			}
		}
		return feedMenuViewAllStatus;
	}

	public void setItemMenuViewAllStatus(boolean status) throws SQLException {
		itemMenuViewAllStatus = status;
	}

	public boolean getItemMenuViewAllStatus() throws BaseException {
		if (itemMenuViewAllStatus == null) {
			Property propertyFeedMenuViewAll = DaoAction.getDaoAction().getPropertyDao()
					.getPropertyByType(Property.PROPERTY_ITEM_MENU_VIEW_ALL);
			if (propertyFeedMenuViewAll.getInteger1().equals(1)) {
				itemMenuViewAllStatus = Boolean.TRUE;
			} else {
				itemMenuViewAllStatus = Boolean.FALSE;
			}
		}
		return itemMenuViewAllStatus;
	}

	public boolean getOfflineStatus() throws BaseException {
		if (offlineStatus == null) {
			Property propertyOffline = DaoAction.getDaoAction().getPropertyDao().getPropertyByType(Property.PROPERTY_OFFLINE_STATUS);
			if (propertyOffline.getInteger1().equals(1)) {
				offlineStatus = Boolean.TRUE;
			} else {
				offlineStatus = Boolean.FALSE;
			}
		}
		return offlineStatus;
	}

	public void fontSizeUp() {
		try {
			this.setDisplayPaneFontSize(1 + this.getDisplayPaneFontSize());
			selectItem(this.selectedItem);
		} catch (Exception e) {
			showError("Ошибка увеличения шрифта", e);
		}
	}

	public void fontSizeDown() {
		try {
			this.setDisplayPaneFontSize(-1 + this.getDisplayPaneFontSize());
			selectItem(this.selectedItem);
		} catch (Exception e) {
			showError("Ошибка уменьшения шрифта", e);
		}
	}

	// actions
	public void showError(String errorMessage, Exception e) {
		mainFrameObservable.showError(errorMessage, e);
	}

	public void showError(Exception e) {
		mainFrameObservable.showError(e);
	}

	public void updateItemsPanel() {
		mainFrameObservable.updateItemsPanel();
	}

	public void updateFeedMenu() {
		mainFrameObservable.updateFeedMenu();
	}

	@Deprecated
	public void setItemsToItemList(List<Item> items) {
		mainFrameObservable.setItemsToItemList(items);
	}

	public void spinnerEnable() {
		spinnerObservable.spinnerEnable();
	}

	public void spinnerDisable() {
		spinnerObservable.spinnerDisable();
	}

	public void doFullScreenMode() {
		isFullScreen = !isFullScreen;
		mainFrameObservable.doFullScreenMode();
	}

	public void doExpandItems(boolean expand) {
		mainFrameObservable.doExpandItems(expand);
	}
	
	public void doExpandWindow() {
		mainFrameObservable.doExpandWindow();
	}

	// obServer
	public void addObserverListener(DisplayPaneListener listener) {
		displayPaneObservable.addObserver(listener);
	}

	public void addObserverListener(MainFrameListener listener) {
		mainFrameObservable.addObserver(listener);
	}

	public void addObserverListener(SpinnerListener listener) {
		spinnerObservable.addObserver(listener);
	}

	public void addObserverListener(LoginListener listener) {
		loginObservable.addObserver(listener);
	}

	public void addObserverListener(SelectItemListener listener) {
		selectItemObservable.addObserver(listener);
	}

	// utils
	private DaoAction getDaoAction() {
		return DaoAction.getDaoAction();
	}

	// properties
	public String getPropertiesFileName() {
		String userHomeDir = System.getProperty("user.home") + File.separator + Constants.RSS_READER_FOLDER_NAME;
		String fileName = userHomeDir + File.separator + "rss.properties";
		return fileName;
	}

	public void setCurrentLocale(Locale currentLocale) {
		this.currentLocale = currentLocale;
	}

	public Locale getCurrentLocale() {
		if (currentLocale == null) {
			Locale locale = null;
			PropertyDao propertyDao = DaoAction.getDaoAction().getPropertyDao();
			try {
				Property propertyLocaleLanguage = propertyDao.getPropertyByType(Property.PROPERTY_LOCALE_LANGUAGE);
				Property propertyLocaleCountry= propertyDao.getPropertyByType(Property.PROPERTY_LOCALE_COUNTRY);
				if (propertyLocaleLanguage.getString1().length()>0 && propertyLocaleCountry.getString1().length()>0) {
					locale = new Locale(propertyLocaleLanguage.getString1(),propertyLocaleCountry.getString1());
				}
			} catch (BaseException e) {
				;
			}
			if (locale == null) {
				locale = Locale.getDefault();
			}
			Locale[] list = getSupportedLocales();
			boolean defaultLocale = false;
			for (Locale l: list) {
				if (locale.equals(l)) {
					defaultLocale = true;
					break;
				}
			}
			if (!defaultLocale) {
				locale  = new Locale("en", "US");
			}
			setCurrentLocale(locale);
		}
		return currentLocale;
	}
}
